使用网络策略Network Policy

Kubernetes网络策略Network Policy提供基于策略的网络控制。如果您希望在IP地址或者端口层面控制网络流量,您可以为集群中特定应用使用网络策略。本文介绍如何使用ACK Serverless集群的网络策略及常见的使用场景。

前提条件

注意事项

  • Network Policy功能仅支持在ACK Serverless集群Pro版ACK集群Pro版使用。

  • 暂不支持IPv6地址的网络策略。

  • 暂不支持NetworkPolicy中EndPort配置。

  • NetworkPolicy规则允许通过LabelSelector选择Namespace或者Pod。但当Pod中的NetworkPolicy数量增大时,不仅会使规则生效时间延长,而且大量的NetworkPolicy规则也会对您的集群管理、问题排查带来困扰,因此建议您集群内的NetworkPolicy数量小于40个。

步骤一:开启网络策略

如需在ACK Serverless集群Pro版中使用Network Policy功能,需按照如下步骤进行操作。

  1. 安装组件Poseidon。

    1. 登录容器服务管理控制台,在左侧导航栏选择集群

    2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择运维管理 > 组件管理

    3. 组件管理页面,单击网络页签,在Poseidon组件所在卡片的右下方,单击安装

    4. 安装组件 Poseidon页面,选中为ECI 实例启用 NetworkPolicy,然后单击确认

      组件安装成功后,会在卡片右上角出现已安装字样。

步骤二:创建可以被其他Pod正常访问的nginx测试应用

通过控制台操作

  1. 登录容器服务管理控制台,在左侧导航栏选择集群

  2. 集群列表页面,单击目标集群名称,然后在左侧导航栏,选择工作负载 > 无状态

  3. 无状态页面,单击使用镜像创建。在创建配置向导页面中,创建一个名称为nginx的应用,并通过Service将其公开。配置完成后,单击创建

    本示例的nginx应用仅需配置以下配置项,其他配置项选择默认配置。关于更多配置说明,请参见使用镜像创建无状态Deployment应用

    页面

    配置项

    说明

    示例值

    应用基本信息

    应用名称

    自定义名称。

    nginx

    副本数量

    按需选择。

    1

    容器配置

    镜像名称

    单击选择镜像,选择所需的镜像并单击确定

    本例选择官方Nginx镜像,可以在搜索页签中,选择Docker官方镜像,然后在文本框中输入nginx进行搜索。

    高级配置

    服务(Service)

    服务(Service)右侧,单击创建设置服务配置项。

    名称:nginx

    类型:

    • 负载均衡

    • 公网访问

    • 新建SLB

    端口映射:

    • 名称:nginx

    • 服务端口:80

    • 容器端口:80

    • 协议:TCP

  4. 再次在无状态页面,单击使用镜像创建。在创建配置向导页面中,创建用于测试访问名称为busybox的客户端应用,用于测试访问上一步中创建的名为nginx的Service。

    本示例的busybox客户端应用仅需配置以下配置项,其他配置项选择默认配置。关于更多配置说明,请参见使用镜像创建无状态Deployment应用

    页面

    配置项

    说明

    示例值

    应用基本信息

    应用名称

    自定义名称。

    busybox

    副本数量

    按需取值。

    1

    容器启动项

    镜像名称

    单击选择镜像,选择所需的镜像并单击确定

    本例选择官方busybox镜像,可以在搜索页签中,选择Docker官方镜像,然后在文本框中输busybox进行搜索。

    容器启动项

    选中stdintty

  5. 验证busybox客户端应用是否可以访问nginx Service。

    1. 无状态页面,找到并单击busybox名称。

    2. 容器组页签下的busybox-{hash值}容器组右侧,单击终端

      image.png

    3. 在busybox的命令行终端中执行wget nginx测试访问nginx。

      connection

      当出现以上信息时,说明您可以在busybox中访问nginx Service。

通过命令行操作

  1. 执行以下命令,创建一个nginx的应用,并通过名称为nginx的Service与其通信。

    创建nginx应用:

    kubectl run nginx --image=nginx

    预期输出:

    pod/nginx created

    查看Pod是否启动:

    kubectl get pod

    预期输出:

    NAME                     READY   STATUS    RESTARTS   AGE
    nginx                    1/1     Running   0          45s

    创建名为nginx的Service:

    kubectl expose pod nginx --port=80

    预期输出:

    service/nginx exposed

    查看Service:

    kubectl get service

    预期输出:

    NAME         TYPE        CLUSTER-IP      EXTERNAL-IP   PORT(S)   AGE
    kubernetes   ClusterIP   172.XX.XX.1     <none>        443/TCP   30m
    nginx        ClusterIP   172.XX.XX.48    <none>        80/TCP    12s
  2. 执行以下命令,创建名称为busybox的Pod,访问名为nginx的Service。

    kubectl run busybox --rm -ti --image=busybox /bin/sh

    预期输出:

    If you don't see a command prompt, try pressing enter.
    / #
    / #

    获取nginx:

    If you don't see a command prompt, try pressing enter.
    / #
    / # wget nginx  # wget nginx需要输入到此处。

    预期输出:

    Connecting to nginx (172.XX.XX.48:80)
    saving to 'index.html'
    index.html           100% |****************************************************************************************************************************************************|   612  0:00:00 ETA
    'index.html' saved

步骤三:使用网络策略

以下几种场景均支持使用网络策略,您可以按需选择。

场景一:通过网络策略限制服务只能被带有特定标签的应用访问

  1. 使用以下YAML模板并执行命令vim policy.yaml,创建名为policy.yaml文件。

    vim policy.yaml

    以下为YAML文件内容。

    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: access-nginx
    spec:
      podSelector:
        matchLabels:
          run: nginx
      ingress:
      - from:
        - podSelector:
            matchLabels:
              access: "true"
  2. 执行以下命令,根据上述的policy.yaml文件创建网络策略。

    kubectl apply -f policy.yaml 

    预期输出:

    networkpolicy.networking.k8s.io/access-nginx created
  3. 执行以下命令,当没有定义访问标签时,测试访问名为nginx的Service,请求会超时,无法访问。

    kubectl run busybox --rm -ti --image=busybox /bin/sh

    测试访问名为nginx的Service

    wget nginx

    预期输出:

    Connecting to nginx (172.19.XX.XX:80)
    wget: can't connect to remote host (172.19.XX.XX): Connection timed out
  4. 执行以下命令,定义访问标签。

    kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh

    测试访问nginx Service

    wget nginx

    预期输出:

    Connecting to nginx (172.21.XX.XX:80)
    saving to 'index.html'
    index.html           100% |****************************************************************************************************************************************************|   612  0:00:00 ETA
    'index.html' saved

    连接nginx的进度为100%时,说明请求成功,可以正常访问nginx服务。

场景二:通过网络策略限制可访问公网服务的来源IP网段

  1. 执行以下命令,为上述名为nginx的应用创建阿里云SLB服务,指定type=LoadBalancer来向外网用户暴露nginx服务。

    vim nginx-service.yaml

    nginx-service.yaml文件模板如下。

    # 将以下YAML内容粘贴至nginx-service.yaml中。
    apiVersion: v1
    kind: Service
    metadata:
      labels:
        run: nginx
      name: nginx-slb
    spec:
      externalTrafficPolicy: Local
      ports:
      - port: 80
        protocol: TCP
        targetPort: 80
      selector:
        run: nginx
      type: LoadBalancer

    执行以下命令,根据上述的nginx-service.yaml文件创建网络策略。

    kubectl apply -f nginx-service.yaml 

    预期输出:

    service/nginx-slb created

    查看应用是否对外暴露nginx服务:

    kubectl get service nginx-slb

    预期输出:

    NAME        TYPE           CLUSTER-IP      EXTERNAL-IP      PORT(S)        AGE
    nginx-slb   LoadBalancer   172.19.xx.xxx   47.110.xxx.xxx   80:32240/TCP   8m
  2. 执行以下命令,访问刚刚创建的SLB的IP地址47.110.xxx.xxx,访问失败。

    wget 47.110.xxx.xxx

    预期输出:

    --2018-11-21 11:46:05--  http://47.110.xx.xxx/
    Connecting to 47.110.XX.XX:80... failed: Connection refused.
    说明

    访问失败的原因是:

    • 配置的nginx Service只能被带有特定标签即access=true的应用访问。

    • 访问SLB的IP地址,是从外部访问Kubernetes,与通过网络策略限制服务只能被带有特定标签的应用访问不同。

    解决方法:修改网络策略,增加允许访问的来源IP地址段。

  3. 执行以下命令,查看本地的IP地址。

    curl myip.ipip.net

    预期输出:

    当前IP:10.0.x.x来自于:中国 北京 北京        # 此处仅为示例,具体请以实际设备为准。
  4. 执行以下命令,修改已经创建的policy.yaml文件。

    vim policy.yaml

    policy.yaml文件修改为如下内容:

    # 以下为YAML文件内容。
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: access-nginx
    spec:
      podSelector:
        matchLabels:
          run: nginx
      ingress:
      - from:
        - podSelector:
            matchLabels:
              access: "true"
        - ipBlock:
            cidr: 100.64.0.0/10
        - ipBlock:
            cidr: 10.0.0.1/24      # 本地IP地址,此处仅为示例,具体请以实际设备为准。

    执行以下命令,根据policy.yaml文件创建网络策略。

    kubectl apply -f policy.yaml 

    预期输出:

    networkpolicy.networking.k8s.io/access-nginx unchanged
    说明
    • 有些网络的出口有多个IP地址,这里请使用/24的地址范围。

    • SLB健康检查地址在100.64.0.0/10地址段内,因此请务必配置100.64.0.0/10

  5. 执行以下命令,创建nginx服务。

    kubectl run busybox --rm -ti --labels="access=true" --image=busybox /bin/sh

    访问nginx服务:

    wget 47.110.XX.XX

    预期输出:

    Connecting to 47.110.XX.XX (47.110.XX.XX:80)
    index.html           100% |***********************************************************|   612  0:00:00 ETA

    连接进度显示100%时,说明成功访问nginx服务。

场景三:通过网络策略限制一个Pod只能访问指定地址

  1. 执行以下命令,获取www.aliyun.com域名解析到的IP地址列表。

    dig +short www.aliyun.com

    预期输出:

    www-jp-de-intl-adns.aliyun.com.
    www-jp-de-intl-adns.aliyun.com.gds.alibabadns.com.
    v6wagbridge.aliyun.com.
    v6wagbridge.aliyun.com.gds.alibabadns.com.
    106.XX.XX.21
    140.XX.XX.4
    140.XX.XX.13
    140.XX.XX.3
  2. 执行以下命令,创建busybox-policy文件。

    vim busybox-policy.yaml

    busybox-policy文件模板如下:

    # 以下为YAML文件内容。
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: busybox-policy
    spec:
      podSelector:
        matchLabels:
          run: busybox
      egress:
      - to:
        - ipBlock:
            cidr: 106.XX.XX.21/32
        - ipBlock:
            cidr: 140.XX.XX.4/32
        - ipBlock:
            cidr: 140.XX.XX.13/32
        - ipBlock:
            cidr: 140.XX.XX.3/32
      - to:
        - ipBlock:
            cidr: 0.0.0.0/0
        - namespaceSelector: {}
        ports:
        - protocol: UDP
          port: 53
    说明

    busybox-policy文件中,配置了去向规则(Egress),限制应用的对外访问。在这里需配置允许UDP请求,否则无法做DNS解析。

  3. 执行以下命令,根据busybox-policy文件创建网络策略。

    kubectl apply -f busybox-policy.yaml 

    预期输出:

    networkpolicy.networking.k8s.io/busybox-policy created
  4. 执行以下命令,创建busybox。

    kubectl run busybox --rm -ti --image=busybox /bin/sh

    访问www.aliyun.com之外的网站,例如,www.taobao.com

    wget www.taobao.com

    预期输出:

    Connecting to www.taobao.com (64.13.XX.XX:80)
    wget: can't connect to remote host (64.13.XX.XX): Connection timed out

    出现can't connect to remote host时,说明失败访问服务。

  5. 执行以下命令,访问www.aliyun.com

    wget www.aliyun.com

    预期输出:

    Connecting to www.aliyun.com (140.205.XX.XX:80)
    Connecting to www.aliyun.com (140.205.XX.XX:443)
    wget: note: TLS certificate validation not implemented
    index.html           100% |***********************************************************|  462k  0:00:00 ETA

    进行显示100%,说明成功访问服务。

场景四:通过网络策略控制命名空间下Pod公网访问权限

说明

此操作有可能影响线上正在访问公网的服务,建议在一个空的命名空间中进行以下操作。

  1. 执行以下命令,创建一个测试的命名空间来验证限制的能力。

    创建一个test-np的命名空间。

    kubectl create ns test-np

    预期输出:

    namespace/test-np created
  2. 执行以下命令,为这个命名空间设置默认的只允许主动访问私网的网络策略规则。

    vim default-deny.yaml

    以下为default-deny.yaml文件的示例模板:

    # 以下为YAML文件内容。
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      namespace: test-np
      name: deny-public-net
    spec:
      podSelector: {}
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      egress:
      - to:
        - ipBlock:
            cidr: 192.168.0.0/16
        - ipBlock:
            cidr: 172.16.0.0/12
        - ipBlock:
            cidr: 10.0.0.0/8

    查看default-deny.yaml文件是否已创建成功。

    kubectl apply -f default-deny.yaml

    预期输出:

    networkpolicy.networking.k8s.io/deny-public-net created

    查看网络策略:

    kubectl get networkpolicy -n test-np

    预期输出:

    NAME                              POD-SELECTOR          AGE
    deny-public-net                   <none>                1m
  3. 执行以下命令,为特殊标签的Pod设置允许访问公网。

    vim allow-specify-label.yaml

    示例标签设置为public-network=true

    # 以下为YAML文件内容。
    kind: NetworkPolicy
    apiVersion: networking.k8s.io/v1
    metadata:
      name: allow-public-network-for-labels
      namespace: test-np
    spec:
      podSelector:
        matchLabels:
          public-network: "true"
      ingress:
      - from:
        - ipBlock:
            cidr: 0.0.0.0/0
      egress:
      - to:
        - ipBlock:
            cidr: 0.0.0.0/0
        - namespaceSelector:
            matchLabels:
              ns: kube-system

    执行如下命令,创建网络策略:

    kubectl apply -f allow-specify-label.yaml

    预期输出:

    networkpolicy.networking.k8s.io/allow-public-network-for-labels created

    查看网络策略:

    kubectl get networkpolicy -n test-np

    预期输出:

    NAME                              POD-SELECTOR          AGE
    allow-public-network-for-labels   public-network=true    1m
    deny-public-net                   <none>                 3m
  4. 执行以下命令验证无特殊标签的Pod不能访问公网。

    kubectl run -it --namespace test-np --rm --image busybox  busybox-intranet
    ping aliyun.com

    预期输出:

    PING aliyun.com (106.11.2xx.xxx): 56 data bytes
    ^C
    --- aliyun.com ping statistics ---
    9 packets transmitted, 0 packets received, 100% packet loss

    显示0 packets received时,说明访问失败。

    说明

    访问失败的原因是:由于通过deny-public-net的网络策略规则限制了test-np的这个命名空间下的Pod的默认的公网访问,所以它下面启动的默认标签的Pod无法访问公网。

  5. 执行以下命令验证带有public-network=true的Pod可以访问服务。

    kubectl run -it --namespace test-np --labels public-network=true --rm --image busybox  busybox-internet
    ping aliyun.com

    预期输出:

    PING aliyun.com (106.11.1xx.xx): 56 data bytes
    64 bytes from 106.11.1xx.xx: seq=0 ttl=47 time=4.235 ms
    64 bytes from 106.11.1xx.xx: seq=1 ttl=47 time=4.200 ms
    64 bytes from 106.11.1xx.xx: seq=2 ttl=47 time=4.182 ms
    ^C
    --- aliyun.com ping statistics ---
    3 packets transmitted, 3 packets received, 0% packet loss
    round-trip min/avg/max = 4.182/4.205/4.235 ms

    显示0% packet loss时,说明成功访问服务。

    说明

    可以正常访问的原因是:由于在allow-public-network-for-labels的网络策略的规则中允许了带有public-network=true的Pod的公网访问,所以在带有这个Label的busybox-internet的Pod可以访问公网。